#ifndef MYCOROUTINE_COROUTINE_H
#define MYCOROUTINE_COROUTINE_H

#include "php_mycoroutine.h"
#include "coroutine.h"

#define DEFAULT_PHP_STACK_PAGE_SIZE 8192

typedef struct _php_coro_args{
	zend_fcall_info_cache *fcc;
	zval *argv;
	uint32_t argc;
} php_coro_args;

typedef struct _php_coro_task
{
    zval *vm_stack_top; // coroutine stack top
    zval *vm_stack_end; // coroutine stack end
    zend_vm_stack vm_stack; // current coroutine stack pointer
    size_t vm_stack_page_size;
    zend_execute_data *execute_data; // current coroutine stack frame
	Coroutine *co;
} php_coro_task;

long PHPCoroutine_create(zend_fcall_info_cache *fci_cache, uint32_t argc, zval *argv);
void PHPCoroutine_save_task(php_coro_task *task);
void PHPCoroutine_save_vm_stack(php_coro_task *task);
php_coro_task* PHPCoroutine_get_task();
void PHPCoroutine_create_func(void *arg);
void vm_stack_init();
void PHPCoroutine_on_close(void *arg);
void PHPCoroutine_restore_task(php_coro_task *task);
void PHPCoroutine_restore_vm_stack(php_coro_task *task);
void PHPCoroutine_vm_stack_destroy();
php_coro_task* get_origin_task(php_coro_task *task);
void PHPCoroutine_on_yield(void *arg);
void PHPCoroutine_on_resume(void *arg);

php_coro_task main_task;

typedef struct _PHPCoroutine{
	long (*create)(zend_fcall_info_cache *fcc, uint32_t argc, zval *argv);
	void (*save_task)(php_coro_task *task);
	void (*save_vm_stack)(php_coro_task *task);
	php_coro_task* (*get_task)();
} PHPCoroutine;

#endif
